import { Alert } from '@aws-amplify/ui-react';

import AppDirectoryAlert from '@/components/AppDirectoryAlert';

import { Example } from '@/components/Example';

Amplify UI Geo is powered by
[Geo APIs](https://docs.amplify.aws/react/build-a-backend/add-aws-services/geo/) and
[Amazon Location Service](https://aws.amazon.com/location/).

### Quick Start

<AppDirectoryAlert />

<Alert variation="info" heading="Create React App setup">
There's a known issue for users of Create React App v4 where the default prod `browserslist` configuration causes build errors when building for production. See the [Create React App Troubleshooting Guide](/getting-started/troubleshooting#create-react-app) to configure Create React App for use with the MapView UI component.
</Alert>

> Prerequisites:
>
> 1. Install `@aws-amplify/ui-react-geo` and `@aws-amplify/geo` with [npm](https://www.npmjs.com/) or [yarn](https://yarnpkg.com/). ( e.g. `npm install @aws-amplify/ui-react-geo @aws-amplify/geo`)
> 2. Create map resources by following the [Amplify Geo documentation](https://docs.amplify.aws/react/build-a-backend/add-aws-services/geo/set-up-geo/).

## MapView

The `MapView` component adds an interactive map to your application.

`MapView` is fully integrated with the open source library [react-map-gl](https://visgl.github.io/react-map-gl/) v7
while using [maplibre-gl-js](https://maplibre.org/maplibre-gl-js/docs/API/) as the map tile source. Please note that `react-map-gl` is a direct dependency that you should NOT install separately. `MapView` is used as a replacement to `react-map-gl`'s [default map](https://visgl.github.io/react-map-gl/docs/api-reference/map)
and supports the same functionality. 

You can import the `MapView` component with related styles and use it in your Amplify application without any
additional configuration.

```js{2,4,11} file=../../../../../../examples/next/pages/ui/components/geo/basic-map/index.page.tsx

```

<Alert role="none" variation="info">
  If the map isn't taking up the entire screen, try resetting your browser's default CSS body margins:
  ```css
  body {
    margin: 0;
  }
  ```
</Alert>

### Setting Initial Viewport

The map's initial viewport can be set with the `initialViewState` property:

```jsx{12}
import { Amplify } from 'aws-amplify';
import { MapView } from '@aws-amplify/ui-react-geo';

import '@aws-amplify/ui-react-geo/styles.css';

// import config from './aws-exports'; // Amplify Gen 1 config
import config from './amplify_outputs.json'

Amplify.configure(config);

export default function InitialViewport() {
  return (
    <MapView
      initialViewState={{
        latitude: 37.8,
        longitude: -122.4,
        zoom: 14,
      }}
    />
  );
}
```

### Usage with react-map-gl

#### Moving Marker

The `Marker` component from the `react-map-gl` library can have dynamic `latitude` and `longitude` properties to create
a moving marker. The marker's position will reflect changes in `latitude` and `longitude`.

```jsx{2,27} file=../../../../../../examples/next/pages/ui/components/geo/map-with-moving-marker/index.page.tsx

```

#### Marker with Popup

The `Popup` component from the `react-map-gl` library can be used with a `Marker` to communicate information to a user
when the marker is clicked. The `offset` property can be used to prevent the popup from overlapping the marker.

```jsx{2,18,26} file=../../../../../../examples/next/pages/ui/components/geo/map-with-marker-popup/index.page.tsx

```

_Note: Ensure `originalEvent.stopPropagation()` is called in the marker click handler. This allows the `showPopup`
state to be handled by the component._

### Animation and Native Map Methods

You may want to access the [native maplibre-gl map object](https://maplibre.org/maplibre-gl-js/docs/API/classes/maplibregl.Map/) from within the component that renders `<MapView>` (to animate a viewport transition with `flyTo`, for example). To accomplish this, you can pass your own ref to `<MapView>` using [React's `useRef` hook](https://legacy.reactjs.org/docs/hooks-reference.html#useref) which will contain the `map` object:

```jsx{15,18,23} file=../../../../../../examples/next/pages/ui/components/geo/map-with-forward-ref/index.page.tsx

```

If you want access to the `map` object in a child component of `<MapView>`, you can use the [useMap hook from react-map-gl](https://visgl.github.io/react-map-gl/docs/api-reference/use-map) instead:

```jsx{1,14,17,26} file=../../../../../../examples/next/pages/ui/components/geo/use-map-hook/index.page.tsx

```

## Location Search

`LocationSearch` provides location search powered by [Amazon Location Service](https://aws.amazon.com/location/) for the
`MapView` component, using the viewport as the proximity for generating results. `LocationSearch` is used as a child
component of `MapView` for which it renders visual markers and information based on its location search results.

You can import the `LocationSearch` component with related styles and use it as a child of `MapView` without any
additional configuration.

```jsx{1,14,17,26} file=../../../../../../examples/next/pages/ui/components/geo/use-map-hook/index.page.tsx

```

### LocationSearch Position

`LocationSearch` can be provided a `position` property when used with `MapView`. The property is not reactive, meaning the
position is fixed after the component mounts. Valid values are `'top-right'`, `'top-left'`, `'bottom-right'`, and
`'bottom-left'`. Default value is `'top-right'`.

```js{12}
import { Amplify } from 'aws-amplify';
import { MapView, LocationSearch } from '@aws-amplify/ui-react-geo';

import '@aws-amplify/ui-react-geo/styles.css';

// import config from './aws-exports'; // Amplify Gen 1 config
import config from './amplify_outputs.json'
Amplify.configure(config);

export default function LocationSearchPosition() {
  return (
    <MapView>
      <LocationSearch position="top-left" />
    </MapView>
  );
}

```

### Standalone LocationSearch

`LocationSearch` can also be used as a standalone component without `MapView`. As a standalone component, `LocationSearch`
provides search results based on an initial proximity. When used as a standlone component, the `proximity` property
with provided `latitude` and `longitude` properties is required.

```js{2,4,16} file=../../../../../../examples/next/pages/ui/components/geo/standalone-location-search/index.page.tsx

```
